package com.hitqz.robot.biz.schedule;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hitqz.robot.api.business.dto.*;
import com.hitqz.robot.api.business.enums.*;
import com.hitqz.robot.api.business.model.dto.FlowPatrolPreAndEndTicketsDto;
import com.hitqz.robot.api.common.entity.*;
import com.hitqz.robot.api.common.enums.SubscribeTopicEnum;
import com.hitqz.robot.api.dispatch.protocol.ProtocolEnum;
import com.hitqz.robot.biz.service.*;
import com.hitqz.robot.biz.websocket.util.BroadcastTopicUtil;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.driver.dto.robot.RobotCustomInfo;
import com.hitqz.robot.driver.model.IRobotPosDto;
import com.hitqz.robot.driver.model.PointDto;
import com.hitqz.robot.driver.parent.RobotDriverService;
import com.hitqz.robot.netty.service.Send2ServerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author xupkun
 * @date 2024/6/21
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class WsSendStatusSchedule {

    private final RobotService robotService;

    private final RobotDriverService robotDriverService;

    private final Send2ServerService send2ServerService;

    private final SysWarningService sysWarningService;

    private final TicketsService ticketsService;

    private final EquipmentFactory equipmentFactory;

    private final TicketsTaskService ticketsTaskService;

    private final RobotEquipmentService robotEquipmentService;

    private final ButtonService buttonService;

    /**
     * 由于调度系统需要更快的坐标数据，所以提高上报频率
     */
    @Scheduled(fixedRate = 300L)
    public void sendStatus() {
        try {
            //StopWatch stopWatch = new StopWatch();
            //stopWatch.start("takePictureComponent");
            IRobotPosDto iRobotPosDto = robotDriverService.getWebPos();
            if (iRobotPosDto != null) {
                Robot robot = robotService.getDefaultRobot();
                //log.info("currentStation : {}", iRobotPosDto.getCurrentStation());
                //if (robot.getDispatch() == 1) {
                //    // 调度上线的情况下，禁止其他的客户端之类的，抢占控制权，防止发生不可控制的意外
                //    robotDriverService.executeOtherCommand(RobotOtherCommandEnum.ROD_CONTROLLER, "");
                //}
                //stopWatch.stop();
                //log.info("get web use ：" + stopWatch.prettyPrint(TimeUnit.SECONDS));
                RobotClientSummaryDto dto = new RobotClientSummaryDto();
                //外设
                RobotEquipmentPanelDto robotEquipmentPanelDto = new RobotEquipmentPanelDto();
                List<RobotEquipment> list = robotEquipmentService.list(Wrappers.<RobotEquipment>lambdaQuery().eq(RobotEquipment::getIsPlay, 1));
                if (list != null && !list.isEmpty()) {
                    //预览地址
                    robotEquipmentPanelDto.setPlayUrls(list.stream().map(RobotEquipment::getPlayUrl).filter(StrUtil::isNotBlank).toList());
                }
                //外设按钮
                robotEquipmentPanelDto.setPanels(robotEquipmentService.getControlButtonList());
                dto.setLogicOnlineStatus(robot.getDispatch());
                dto.setEquipmentPanel(robotEquipmentPanelDto);
                RobotStatusDto robotStatusDto = new RobotStatusDto();

                // 顶升状态 判断
                if (RobotModelEnum.AGV.getFlag().equals(robot.getRobotModel())) {
                    // 计算顶升状态
                    R result = robotDriverService.executeOtherCommand(RobotOtherCommandEnum.JACKING_STATUS, null);
                    Object data = result.getData();
                    if (!(data instanceof Integer)) {
                        log.warn("获取顶升状态失败，返回数据不是Integer类型");
                        return;
                    }
                    int jackStatus = (Integer) data;

                }

                dto.setClientId(robot.getRobotSn());
                robotStatusDto.setName(robot.getRobotName());
                robotStatusDto.setSn(robot.getRobotSn());
                robotStatusDto.setIp(robot.getIpAddress());
                robotStatusDto.setOnlineStatus(Integer.valueOf(robot.getOnlineStatus()));
                robotStatusDto.setOnlineStatusStr(robot.getOnlineStatus().equals("1") ? "在线" : "离线");
                robotStatusDto.setErrorStatus(1);
                robotStatusDto.setErrorStatusStr("正常");
                robotStatusDto.setBattery(String.valueOf(iRobotPosDto.getBatteryLevel()));
                //robotStatusDto.setBattery("20.0");
                robotStatusDto.setVoltage(String.valueOf(iRobotPosDto.getVoltage()));
                robotStatusDto.setCurrent(String.valueOf(iRobotPosDto.getCurrent()));
                robotStatusDto.setCurrentDirection(iRobotPosDto.getCurrentDirection() == null ? "放电" : iRobotPosDto.getCurrentDirection());
                robotStatusDto.setChargeStatus(iRobotPosDto.isCharging() ? 1 : 0);
                robotStatusDto.setChargeStatusStr(iRobotPosDto.isCharging() ? "充电中" : "正常速度控制");
                robotStatusDto.setIsFull(iRobotPosDto.getFull());

                robotStatusDto.setNavStatus(iRobotPosDto.getNavStatus());
                robotStatusDto.setNavStatusStr(NavEnum.NAV_STATUS.get(iRobotPosDto.getNavStatus()));
                robotStatusDto.setTaskStatus(iRobotPosDto.getTaskStatus());
                robotStatusDto.setTaskStatusStr(iRobotPosDto.getTaskStatusStr());
                robotStatusDto.setTemperature(String.valueOf(iRobotPosDto.getTemperature()));

                robotStatusDto.setSpeed(String.valueOf(iRobotPosDto.getSpeed()));
                robotStatusDto.setWorkStatus(Integer.parseInt(robot.getWorkStatus()));
                robotStatusDto.setWorkStatusStr(WorkStatusEnum.CMD_ROBOT_STATUS.get(robot.getWorkStatus()).getDesc());
                robotStatusDto.setEmergencyStop(iRobotPosDto.isEmergency() ? 1 : 0);
                robotStatusDto.setEmergencyStopStr(iRobotPosDto.isEmergency() ? "急停触发" : "未触发");

                dto.setStatus(robotStatusDto);
                RobotPositionDto robotPositionDto = new RobotPositionDto();
                robotPositionDto.setMapCode(robot.getMapCode());
                robotPositionDto.setUrl(iRobotPosDto.getUrl());
                robotPositionDto.setWebControlSpeed(iRobotPosDto.getWebControlSpeed());

                /**
                 * 机器人像素位置
                 */
                RobotLaserPosDto robotPixelPos = new RobotLaserPosDto();
                robotPixelPos.setYaw(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelAngle())));
                robotPixelPos.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelX())));
                robotPixelPos.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getPixelY())));
                robotPixelPos.setZ(0.0D);
                robotPositionDto.setPixelPos(robotPixelPos);

                /**
                 * 机器人形式过的路径
                 */
                ArrayList<RobotPosDto> passedPath = new ArrayList<>();
                for (PointDto pointDto : CollUtil.emptyIfNull(iRobotPosDto.getPassedPath())) {
                    RobotPosDto robotPosDto = new RobotPosDto();
                    robotPosDto.setX(pointDto.getX());
                    robotPosDto.setY(pointDto.getY());
                    passedPath.add(robotPosDto);
                }
                robotPositionDto.setPassedPath(passedPath);


                /**
                 * 机器人激光位置
                 */
                RobotLaserPosDto robotLaserPosDto = new RobotLaserPosDto();
                robotLaserPosDto.setYaw(Double.parseDouble(String.valueOf(iRobotPosDto.getAngle())));
                robotLaserPosDto.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getX())));
                robotLaserPosDto.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getY())));
                robotLaserPosDto.setZ(0.0D);
                // 最近的距离
                robotLaserPosDto.setNearPosCode(iRobotPosDto.getCurrentStation());
                robotLaserPosDto.setLastPosCode(iRobotPosDto.getLastStation());
                robotPositionDto.setLaserPos(robotLaserPosDto);

                /**
                 * 二维码位置
                 */
                RobotQRPosDto robotQRPosDto = new RobotQRPosDto();
                robotQRPosDto.setLabel("");
                robotQRPosDto.setAngle(0.0D);
                robotQRPosDto.setX(0.0D);
                robotQRPosDto.setY(0.0D);
                robotQRPosDto.setZ(0.0D);
                robotPositionDto.setQrCodePos(robotQRPosDto);
                RobotPosDto robotPosDto = new RobotPosDto();
                robotPosDto.setX(Double.parseDouble(String.valueOf(iRobotPosDto.getX())));
                robotPosDto.setY(Double.parseDouble(String.valueOf(iRobotPosDto.getY())));
                robotPosDto.setZ(0.0D);
                robotPositionDto.setMileage(robotPosDto);
                robotPositionDto.setLaser2D(Lists.newArrayList());
                robotPositionDto.setLaser3D("");
                dto.setPosition(robotPositionDto);
                RobotTaskDto robotTaskDto = new RobotTaskDto();
                RobotTransportTaskDto robotTransportTaskDto = new RobotTransportTaskDto();
                if (robot.getWorkStatus().equals(WorkStatusEnum.WORK.getCode())) {
                    Tickets tickets = ticketsService.getOne(Wrappers.<Tickets>lambdaQuery()
                            .eq(Tickets::getStatus, TicketsStatusEnum.STATUS_EXECUTING.getCode())
                            .orderByDesc(Tickets::getId)
                            .last("limit 1"));
                    if (tickets != null) {
                        robotTaskDto.setId(String.valueOf(tickets.getServerId()));
                        robotTaskDto.setName(tickets.getName());
                        robotTaskDto.setStartTime(DateUtil.format(tickets.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
                        robotTaskDto.setStatusStr("执行中");
                        if (robot.getRobotModel().equals(RobotModelEnum.AGV.getFlag()) && StrUtil.isNotBlank(tickets.getContent())) {
                            robotTaskDto.setType("3");
                            TicketsTask ticketsTask = ticketsTaskService.getOne(Wrappers.<TicketsTask>lambdaQuery()
                                    .eq(TicketsTask::getTicketsId, tickets.getId())
                                    .eq(TicketsTask::getStatus, TicketsStatusEnum.TICKETS_TASK_EXECUTING.getCode()).last(" limit 1")
                            );
                            FlowPatrolPreAndEndTicketsDto ticketsDto = JSONObject.parseObject(ticketsTask.getParseOrderParams()
                                    , FlowPatrolPreAndEndTicketsDto.class);

                            String sourceName = Optional.ofNullable(ticketsDto.getModalData().get("sourcePosName"))
                                    .orElse(ticketsDto.getModalData().get("sourcePosCode")).toString();
                            String targetName = Optional.ofNullable(ticketsDto.getModalData().get("targetPosName"))
                                    .orElse(ticketsDto.getModalData().get("targetPosCode")).toString();
                            robotTransportTaskDto.setStartSite(sourceName);
                            robotTransportTaskDto.setTargetSite(targetName);
                        } else {
                            robotTransportTaskDto.setStartSite("");
                            robotTransportTaskDto.setTargetSite("");
                        }
                    }
                } else {
                    robotTaskDto.setId("");
                    robotTaskDto.setName("");
                    robotTaskDto.setType("");
                    robotTaskDto.setStatus("");
                    robotTaskDto.setStartTime("");
                }
                robotTaskDto.setTransportTask(robotTransportTaskDto);
                dto.setTask(robotTaskDto);
                RobotControlPanelDto robotControlPanelDto = new RobotControlPanelDto();

                // 使用方法
                List<Button> buttonsDb = buttonService.list(Wrappers.<Button>lambdaQuery().eq(Button::getObject, "robot").eq(Button::getIsShow, true));
                List<RobotControlButtonDto> buttons = BeanUtil.copyToList(buttonsDb, RobotControlButtonDto.class);
                robotControlPanelDto.setButtons(buttons);
                dto.setControlPanel(robotControlPanelDto);


                // 机器人报警
                List<RobotWarningDto> robotWarningDtos = Lists.newArrayList();
                List<SysWarning> sysWarnings = sysWarningService.list(Wrappers.<SysWarning>lambdaQuery().orderByDesc(SysWarning::getId)
                        .ne(SysWarning::getCode, "999")
                        .last("limit 10"));
                sysWarnings.stream().forEach(t -> {
                    RobotWarningDto robotWarningDto = new RobotWarningDto();
                    robotWarningDto.setType("0");
                    robotWarningDto.setTitle("[" + robot.getRobotName() + "] " + t.getTitle());
                    robotWarningDto.setContent(t.getContent());
                    robotWarningDto.setTime(DateUtil.format(t.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
                    robotWarningDto.setLevel(1);
                    robotWarningDto.setPath(t.getPaths());
                    robotWarningDtos.add(robotWarningDto);
                });
                dto.setWarning(robotWarningDtos);

                //  巡检报警
                List<SysWarning> errorChecks = sysWarningService.list(Wrappers.<SysWarning>lambdaQuery().orderByDesc(SysWarning::getId)
                        .eq(SysWarning::getCode, "999")
                        .last("limit 10"));
                List<RobotWarningDto> errors = Lists.newArrayList();
                errorChecks.stream().forEach(t -> {
                    RobotWarningDto robotWarningDto = new RobotWarningDto();
                    robotWarningDto.setType("0");
                    robotWarningDto.setTitle(t.getContent());
                    robotWarningDto.setContent(t.getContent());
                    robotWarningDto.setTime(DateUtil.format(t.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
                    robotWarningDto.setLevel(1);
                    robotWarningDto.setPath(t.getPaths());
                    errors.add(robotWarningDto);
                });
                dto.setErrorChecks(errors);

                // 其他状态信息
                RobotOtherInfoDto robotOtherInfoDto = new RobotOtherInfoDto();
                robotOtherInfoDto.setRobotLength(robot.getRobotLength());
                robotOtherInfoDto.setRobotWidth(robot.getRobotWidth());
                robotOtherInfoDto.setRobotAngleLength(robot.getRobotAngleLength());
                dto.setOtherInfo(robotOtherInfoDto);
                List<RobotCustomInfo> robotCustomInfos = robotDriverService.getCustomInfo();
                if (CollUtil.isNotEmpty(robotCustomInfos)) {
                    List<RobotCustomInfoDto> robotCustomInfoDtos = Lists.newArrayList();
                    robotDriverService.getCustomInfo().stream().forEach(t -> {
                        robotCustomInfoDtos.add(new RobotCustomInfoDto(t.getLabel(), t.getValue(), t.getKey()));
                    });
                    robotOtherInfoDto.setCustomInfos(robotCustomInfoDtos);
                }
                String data = JSONObject.toJSONString(dto);
                if (log.isDebugEnabled()) {
                    log.debug("send data to robot" + data);
                }
                try {
                    // 传给前端
                    BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_INFO.getTopic(), data);
                } catch (Exception e) {

                }
                try {
                    // 发送给服务端, 保证传给服务端，不然无法执行任务
                    send2ServerService.send2ServerData(Integer.valueOf(ProtocolEnum.ROBOT_SUMMARY.getCmd()), JSONObject.toJSONString(dto));
                } catch (Exception e) {

                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 报警信息
     */
    @Scheduled(fixedRate = 3000L)
    public void sendWarning() {
        SysWarning sysWarning = sysWarningService.getOne(Wrappers.<SysWarning>lambdaQuery()
                .eq(SysWarning::getStatus, 0)
                .orderByDesc(SysWarning::getId)
                .last("limit 1"));
        RobotWarningDto robotWarningDto = null;
        if (sysWarning != null) {
            robotWarningDto = new RobotWarningDto();
            robotWarningDto.setId(sysWarning.getId());
            robotWarningDto.setType("0");
            robotWarningDto.setTitle(sysWarning.getTitle());
            robotWarningDto.setContent(sysWarning.getContent());
            robotWarningDto.setTime(DateUtil.format(sysWarning.getWarningTime(), "yyyy-MM-dd HH:mm:ss"));
            robotWarningDto.setLevel(1);
            robotWarningDto.setPath(sysWarning.getPaths());
        } else {
            robotWarningDto = new RobotWarningDto();
            robotWarningDto.setId(-1L);
        }
        BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_WARNING.getTopic(), JSONObject.toJSONString(robotWarningDto));
    }


    /**
     * 挂轨--语音对讲-进行页面通知
     */
    @Scheduled(fixedRate = 3000L)
    public void sendSpeak() {
        R result = robotDriverService.executeOtherCommand(RobotOtherCommandEnum.SPEAK_REQUEST, "");
        BroadcastTopicUtil.broadcastMessageByTopic(SubscribeTopicEnum.ROBOT_SPEAK_REQUEST.getTopic(), JSONObject.toJSONString(result));
    }


    //@Scheduled(fixedRate = 2000L)
    //public void sendEquipmentStatus(){
    //    List<RobotEquipment> robotEquipments = robotEquipmentService.list();
    //    for (RobotEquipment robotEquipment : robotEquipments) {
    //        IEquipmentService service = equipmentFactory.getServiceByBrand(robotEquipment.getBrand());
    //        QueryParamsDto queryParamsDto = new QueryParamsDto();
    //        queryParamsDto.setUsername(robotEquipment.getUsername());
    //        queryParamsDto.setPassword(robotEquipment.getPassword());
    //        queryParamsDto.setPort(robotEquipment.getPort());
    //        queryParamsDto.setIp(robotEquipment.getIp());
    //        queryParamsDto.setChannel(robotEquipment.getChannel());
    //        if (!NetUtil.ping(robotEquipment.getIp())){
    //            continue;
    //        }
    //        if (service != null) {
    //            BroadcastTopicUtil.broadcastMessageByRandomId(
    //                    robotEquipment.getId().intValue(), SubscribeTopicEnum.ROBOT_EQUIPMENT_STATUS,
    //                    JSONObject.toJSONString(service.getEquipmentParams(queryParamsDto)));
    //        }
    //    }
    //
    //}

    /**
     * 挂轨--语音对讲-进行页面通知
     */
    //@Scheduled(fixedRate = 1000L)
    //public void realManArmStatus(){
    //    IEquipmentService service = equipmentFactory.getServiceByBrand(BrandEnum.REALMAN.getEnStr());
    //    if (null == service) {
    //        return;
    //    }
    //    RobotEquipment equipment = robotEquipmentService.getOne(Wrappers.lambdaQuery(RobotEquipment.class)
    //            .eq(RobotEquipment::getBrand, BrandEnum.REALMAN.getEnStr()));
    //    if (null == equipment) {
    //        return;
    //    }
    //    QueryParamsDto queryParamsDto = new QueryParamsDto();
    //    queryParamsDto.setIp(equipment.getIp());
    //    queryParamsDto.setPort(equipment.getPort());
    //    try {
    //        IEquipmentCmdResult result = service.executeCmd(queryParamsDto, true, EquipmentCmdEnum.GET_CURRENT_ARM_STATE, null);
    //        send2ServerService.send2ServerData((int) ProtocolEnum.ROBOT_REAL_MAN_ARM_STATUS.getCmd(), JSONObject.toJSONString(result));
    //    } catch (Exception e) {
    //        log.error("获取瑞尔曼机械臂状态失败", e);
    //    }
    //}


}
